/*
*
* This file is part of QMapControl,
* an open-source cross-platform map widget
*
* Copyright (C) 2007 - 2008 Kai Winter
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with QMapControl. If not, see <http://www.gnu.org/licenses/>.
*
* Contact e-mail: kaiwinter@gmx.de
* Program URL   : http://qmapcontrol.sourceforge.net/
*
*/

#ifndef LAYERMANAGER_H
#define LAYERMANAGER_H

#include <QObject>
#include <QMap>
#include <QListIterator>
#include "layer.h"
#include "mapadapter.h"
#include "mapcontrol.h"

namespace qmapcontrol
{
	class Layer;
	class MapAdapter;
	class MapControl;

	class LayerManager;
	
	//! Handles Layers and viewport related settings
	/*!
	 * This class handles internally all layers which were added to the MapControl.
	 * It also stores values for scrolling.
	 * It initiates the creation of a new offscreen image and on zooming the zoom images gets here created.
	 *	@author Kai Winter <kaiwinter@gmx.de>
 	*/
	class LayerManager : public QObject
	{
		Q_OBJECT
		public:
			LayerManager(MapControl*, QSize);
			~LayerManager();
		
		//! returns the coordinate of the center of the map
		/*!
			 * @return returns the coordinate of the middle of the screen
		 */
			QPointF currentCoordinate() const;
		
		//! returns the current offscreen image
		/*!
			 * @return the current offscreen image
		 */
			QPixmap getImage() const;
		
		//! returns the layer with the given name
		/*!
			 * @param  layername name of the wanted layer
			 * @return the layer with the given name
		 */
			Layer* layer(const QString&) const;
		
		//! returns the base layer
		/*!
			 * This will return the base layer of the LayerManager.
			 * The base layer is the one which is used to do internal coordinate calculations.
			 * @return the base layer 
		 */
			Layer* layer() const;
		
		//! returns the names of all layers
		/*!
			 * @return returns a QList with the names of all layers
		 */
			QList<QString> layers() const;

		//! sets the middle of the map to the given coordinate
		/*!
			 * @param  coordinate the coordinate which the view´s middle should be set to
		 */
			void setView(const QPointF& coordinate);
		
		//! sets the view, so all coordinates are visible
		/*!
			 * @param  coordinates the Coorinates which should be visible
		 */
			void setView(const QList<QPointF> coordinates);
		
		//! sets the view and zooms in, so all coordinates are visible
		/*!
			 * The code of setting the view to multiple coordinates is "brute force" and pretty slow.
			 * Have to be reworked.
			 * @param  coordinates the Coorinates which should be visible
		 */
			void			setViewAndZoomIn		(const QList<QPointF> coordinates);
		
		//! zooms in one step
			void zoomIn();
		
		//! zooms out one step
			void zoomOut();
		
		//! sets the given zoomlevel
		/*!
			 * @param zoomlevel the zoomlevel
		 */
			void setZoom(int zoomlevel);
	
		//! The Viewport of the display
		/*!
			 * Returns the visible viewport in world coordinates
			 * @return the visible viewport in world coordinates
		 */
			QRectF getViewport() const;
		
		//! scrolls the view
		/*! 
			 * Scrolls the view by the given value in pixels and in display coordinates
			 * @param  offset the distance which the view should be scrolled
		*/
			void scrollView(const QPoint& offset);
		
		//! forwards mouseevents to the layers
		/*!
				* This method is invoked by the MapControl which receives Mouse Events.
			 * These events are forwarded to the layers, so they can check for clicked geometries.
			 * @param  evnt the mouse event
		 */
			void mouseEvent(const QMouseEvent* evnt);

		//! returns the middle of the map in projection coordinates
		/*!
			 * 
			 * @return the middle of the map in projection coordinates
		 */
			QPoint getMapmiddle_px() const;
		
			void forceRedraw();
			void removeZoomImage();
		
		//! adds a layer
		/*!
			 * If multiple layers are added, they are painted in the added order.
			 * @param layer the layer which should be added
		 */
			void addLayer(Layer* layer);
		
		//! returns the current zoom level
		/*!
			 * @return returns the current zoom level
		 */
			int currentZoom() const;
		
			void drawGeoms(QPainter* painter);
			void drawImage(QPainter* painter);
	
		private:
			LayerManager& operator=(const LayerManager& rhs);
			LayerManager(const LayerManager& old);
		//! This method have to be invoked to draw a new offscreen image
		/*!
			 * @param clearImage if the current offscreeen image should be cleared
			 * @param showZoomImage if a zoom image should be painted
		 */
			void newOffscreenImage(bool clearImage=true, bool showZoomImage=true);
			inline bool checkOffscreen() const;
			inline bool containsAll(QList<QPointF> coordinates) const;
			inline void moveWidgets();
			inline void setMiddle(QList<QPointF> coordinates);
		
			MapControl* mapcontrol;
			QPoint screenmiddle;		// middle of the screen
			QPoint scroll;				// scrollvalue of the offscreen image
			QPoint zoomImageScroll;	// scrollvalue of the zoom image
		
			QSize size;		// widget size
			QSize offSize;	// size of the offscreen image
		
			QPixmap composedOffscreenImage;
			QPixmap composedOffscreenImage2;
			QPixmap zoomImage;
		
			QList<Layer*>	mylayers;
		
			QPoint mapmiddle_px;	// projection-display coordinates
			QPointF mapmiddle;	// world coordinate

			QMutex scrollMutex;
			QPoint whilenewscroll;
			mutable QMutex refreshMutex;	
		
		public slots:
			void updateRequest(QRectF rect);
			void updateRequest();
			void resize(QSize newSize);
	};
}
#endif
